# -*- coding: iso-8859-1 -*-
import msnp2p, msnlib
import random, base64

# Stores each file transfer session
class FTSession:
	def __init__(self, status = 0, sessionID = '', filename = '', ContextFileSize = ''):
		# Statuses:
		# 0 - got invitation (waiting for accept or cancel response)
		# 1 - transfering
		# 2 - completed
		# 3 - canceled
		self.status = status
		self.filesize = 0
		self.transfered = 0
		self.sessionID = sessionID
		self.filename = filename
		self.Contextfilesize = ContextFileSize

	def getPercentCompleted(self):
		perc = 0
		if self.filesize:
			perc = self.transfered * 100.0 / self.filesize
		return perc

	def chgStatus(self, status):
		self.status = status

# Stores all open file transfer sessions from one sender
class SessionsWithUser:
	def __init__(self, sender):
		self.sender = sender
		self.sessions = []		

	def count(self):
		return len(self.sessions)

	def addSession(self, status = '', sessionID = '', filename = '', filesize = 0):
		self.sessions.append(FTSession(status, sessionID, filename, filesize))

	def cleanSessions(self):
		for s in self.sessions:
			if s.status in (2, 3):
				self.sessions.remove(s)

	def getSession(self, sessionID):
		for s in self.sessions:
			if s.sessionID == sessionID:
				return s
				break

	def acceptInvitation(self, mam, tid, message, nd, sessionID):
		msnlib.debug('-------------------------------------------\n' + \
		'Accepting invitation for ft\n'+ \
		'-------------------------------------------\n')
		msnlib.debug('MSG Enviado:\n')

		sender = tid.split(' ')[0]
		via = message.split("Via: MSNSLP/1.0/TLP ;branch={")[1].split("}")[0]
		callID =  message.split("Call-ID: {")[1].split("}")[0]
		myID = random.randint(0, 50000)

		# msg header
		msgHeader = "MIME-Version: 1.0\r\n"
		msgHeader += "Content-Type: application/x-msnmsgrp2p\r\n"
		msgHeader += "P2P-Dest: "+ sender + "\r\n\r\n"

		# body
		s = 'MSNSLP/1.0 200 OK\r\n'
		s += 'To: <msnmsgr:' + sender + '>\r\n'
		s += 'From: <msnmsgr:' + mam.m.email + '>\r\n'
		s += 'Via: MSNSLP/1.0/TLP ;branch={' + via + '}\r\n'
		s += 'CSeq: 1 \r\n'
		s += 'Call-ID: {' + callID + '}\r\n'
		s += 'Max-Forwards: 0\r\n'
		s += 'Content-Type: application/x-msnmsgr-sessionreqbody\r\n'
		content = 'SessionID: ' + str(sessionID) + '\r\n\r\n\0'		
		s += 'Content-Length: ' + str(len(content)) + '\r\n\r\n'
		s += content

		# binary header
		header = msnp2p.BinHeader()
		header.setIdentifier(myID)
		header.setAcknowledgedIdentifier(random.randint(0, 50000))
		header.setTotalDataSize(len(s))
		header.setMessageLength(len(s))		

		tid = nd.get_tid()
		nd.fd.send('MSG ' + str(tid) + ' D ' + \
		str(len(msgHeader) + len(s) + 52) + '\r\n' + msgHeader + \
		header.getData() + s + '\0\0\0\0')
		
		# DEBUG
		msnlib.debug('MSG ' + str(tid) + ' D ' + \
		str(len(msgHeader) + len(s) + 52) + '\r\n' + msgHeader + \
		header.getData() + s + '\0\0\0\0')
		msnlib.debug(' -------------------------------------------\n\n')

	def process(self, mam, tid, message, nd, parameters = ''):
		msnlib.debug('-------------------------------------------\n' + \
		'Processing SessionsWithUser x msg\n'+ \
		'-------------------------------------------')
		# got new invitation..
		if 'AppID: 2' in message and 'Context' in message:
			i = 4-(len(parameters['Context'])%4)
			context = parameters['Context']
			for e in range(i):
				context = context + "="
			context = FTContext(base64.b64decode(context))
		
			# Create ft session
			self.addSession(0, parameters['SessionID'], str(context.filename), \
			str(context.file_size))
		
			# accept Invitation.
			session = self.getSession(parameters['SessionID'])
			session.chgStatus(1)			
			self.acceptInvitation(mam, tid, message, nd, parameters['SessionID'])

		# got data..	
		else:
			# Identify session
			session = self.getSession(parameters['header'].getSessionID())

			# process new data pack..
			# get data
			session.transfered = parameters['header'].getDataOffset()
			chunk = message.split('\r\n\r\n')[1][48:-4]
			
			# save it
			pFile = open(mam.config['coming_files_path'] + session.filename, 'ab')
			pFile.write(chunk)
			pFile.close()

			# check if completed
			if session.getPercentCompleted == 100:
				session.chgStatus(2)

# Stores all the SessionsWithUser from the different senders
class ftManager:
	def __init__(self):
		self.sessions = []

	# Number of users whom have file transfers with us.
	def count(self):
		return len(self.sessions)

	def hasSessionsWith(self, sender):
		res = 0
		for s in self.sessions:
			if s.sender == sender:
				res = 1
				break
		return res

	def listSessions(self):
		msnlib.debug('--------------')
		msnlib.debug('FT sessions:')
		for s1 in self.sessions:			
			msnlib.debug(s1.sender + '\n')
			for s2 in s1.sessions:
				msnlib.debug('\t' + s2.filename + '\n')			

	def gotFTData(self, parameters):
		res = 0
		sID = msnp2p.BinHeader(parameters['header']).getSessionID()
		for s1 in self.sessions:
			for s2 in s1.sessions:
				if s2.sessionID == sID:
					res = 1
					break
			if res == 1:
				break
		return res

	def cleanSessions(self):
		for s in self.sessions:
			s.cleanSessions()

	def addSessionsWith(self, sender):
		self.sessions.append(SessionsWithUser(sender))

	def getSessionsWith(self, sender):
		for s in self.sessions:
			if s.sender == sender:
				return s

	def process(self, mam, tid, message, nd, parameters = ''):
		msnlib.debug('-------------------------------------------\n' + \
		'Processing FTMANAGER x msg\n'+ \
		'-------------------------------------------')
		tid_copy = tid
		sender = tid_copy.split(' ')[0]
		if not self.hasSessionsWith(sender):
			self.addSessionsWith(sender)
		self.getSessionsWith(sender).process(mam, tid, message, nd, parameters)

# This class represent File Transfer Context
class FTContext(msnp2p.ByteArray):
	def __init__(self, data = None):
		msnp2p.ByteArray.__init__(self, 25)
		self.__filename = ''
		self.name = ''
		self.file_size = 0
		if data != None:
			self.fill(data)

	def set_file_size(self, qword):
		'''set the value of data offset'''
		self.setDword(8, qword)

	def get_file_size(self):
		'''get the value of data offset'''
		return self.getDword(8)

	file_size = property(fset=set_file_size, fget=get_file_size)

	def set_filename(self, data):
		'''set the value of filename'''
		data = data+'\0'*(548-len(data))
		self.__filename = data.encode('utf-16-le')

	def get_filename(self):
		'''get the value of filename'''
		return self.__filename.decode('utf-16-le').replace('\0', '')

	filename = property(fset=set_filename, fget=get_filename)

	def print_fields(self):
		msnlib.debug('-------------------------------------------\n' + \
		'File size:               ' + str(self.file_size) + \
		'Filename:                ' + str(self.filename) + \
		'-------------------------------------------\n')

	def fill(self, data):
		'''fill the object with the data provided'''
		self.set_file_size(self.getDwordFromData(data, 8))
		self.__filename = data[20:540]

# Function to parse the parameters of a message 
def getParameters(s):
	'''parse a message and create and return a dict with the values'''
	d = {}
	try:
		header = s.split('\r\n\r\n')[1][:48]
		d['header'] = header
	except:
		pass
	for i in s.split('\r\n'):
		l = i.split(': ')
		if len(l) == 2:
			d[l[0]] = l[1]
	return d
